package com.mssh.login.core;

import lombok.SneakyThrows;
import org.crazycake.shiro.IRedisManager;
import org.crazycake.shiro.serializer.RedisSerializer;
import org.crazycake.shiro.serializer.StringSerializer;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.util.SerializationUtils;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 熳殊沙华
 * @Date: 2025/03/27/16:54
 * @Description:
 */
public class RedisManager implements IRedisManager {

    private RedisTemplate<String, Object> redisTemplate;

    private RedisSerializer<String> keySerializer = new StringSerializer();

    public RedisManager(RedisConnectionFactory connectionFactory) {
        this.redisTemplate = new RedisTemplate<>();
        this.redisTemplate.setConnectionFactory(connectionFactory);
        this.redisTemplate.afterPropertiesSet();
    }

    @SneakyThrows
    @Override
    public byte[] get(byte[] key) {
        String strKey = keySerializer.deserialize(key);
        Object value = redisTemplate.opsForValue().get(strKey);
        return value != null ? SerializationUtils.serialize(value) : null;
    }

    @SneakyThrows
    @Override
    public byte[] set(byte[] key, byte[] value, int expire) {
        String strKey = keySerializer.deserialize(key);
        redisTemplate.opsForValue().set(strKey, SerializationUtils.deserialize(value), expire, TimeUnit.SECONDS);
        return value;
    }

    @SneakyThrows
    @Override
    public void del(byte[] bytes) {
        String strKey = keySerializer.deserialize(bytes);
        Boolean deleted = redisTemplate.delete(strKey);
    }

    @Override
    public Long dbSize(byte[] bytes) {
        return redisTemplate.execute((RedisCallback<Long>) connection -> {
            // 直接调用Redis命令
            return connection.serverCommands().dbSize();
        });
    }

    @SneakyThrows
    @Override
    public Set<byte[]> keys(byte[] pattern) {
        String strPattern = keySerializer.deserialize(pattern);
        Set<byte[]> result = new HashSet<>();
        // 使用SCAN代替KEYS避免阻塞
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions()
                    .match(strPattern)
                    .count(1000)
                    .build());
            while (cursor.hasNext()) {
                result.add(cursor.next());
            }
            return null;
        });
        return result;
    }
}
